#ifndef RENDER_H_INCLUDED
#define RENDER_H_INCLUDED


class render_engine {
    public:

    r_rect  b_box; // tag bounding box

    #define MAX_TABLE_COLS (50)
    #define MAX_TABLE_ROWS (50)

    struct _table
    {
        _table() : num_cols(0), num_rows(0), max_width(0)
        {
            memset(col_widths,0,MAX_TABLE_COLS*sizeof(int));
        };

        int num_cols;
        int num_rows;
        int max_width; // table maximum width

        int col_widths[MAX_TABLE_COLS]; // max of 50 right now
        int col_min_widths[MAX_TABLE_COLS]; // max of 50 right now
        int col_fixed_widths[MAX_TABLE_COLS]; // set by "width"
        int col_height[MAX_TABLE_ROWS]; // height of the row
        int row_fixed_heights[MAX_TABLE_ROWS]; // set by "height"

        // working vars
        int x_start;
        int y_start;
        int row_i;
        int col_i;


    }table_data;

    fonts           fnts;
    texture_cache*  tx;
    html_document*  doc;

    char*           base_path;

    // html render varables

    int             page_width;
    int             page_height;
    int             view_x; // x modifier for viewing area
    int             view_y; // y modifier for viewing area

    int             p_y;
    int             p_x;
    int             nextline;
    int             nextx;


    html_tag*               last_tag;


    vector<render_object*>   r_objs;
    render_object*           r_co;

    render_engine(char* _path, html_document*  _doc,int _pw) : tx(0), doc(_doc), base_path(_path),
        page_width(_pw), page_height(0), view_x(0), view_y(0), p_y(0), p_x(0), nextline(0), nextx(0)
    {
        tx = new texture_cache;
        if (!tx) exit(0);
    };

    ~render_engine()
    {
        delete tx;

        for(int i =0; i<(int)r_objs.size();i++)
            delete r_objs[i];
    };

    // return the value of the attribute you pass in if found.
    // if this tag has parent tags it will traverse the parent to find the attribute.
    char* get_attribute_value(html_tag *start, unsigned long attrib_hash)
    {
        char* result = 0;
        html_attrib* c = start->first_child;

        while(c) {

            if (attrib_hash == c->attrib_hash) {
                result = (char*)c->value.c_str();
                break;
            }

            c = c->next;
        }

        return result;

    };

    int get_attribute_value_int(html_tag *start, unsigned long attrib_hash, unsigned long tag_hash )
    {
        int result = 0;
        html_attrib* c = start->first_child;

        while(c) {
            if (tag_hash == c->parent->tag_hash)
            {
                if (attrib_hash == c->attrib_hash) {
                    result = atoi(c->value.c_str());
                    break;
                }
            }
            c = c->next;
        }

        return result;

    };

    SDL_Surface* load_image(char* p)
    {
        char full_img_path[255] = {0};
        sprintf(full_img_path,"%s%s",base_path,p);

        return tx->texture_lookup(full_img_path);

    };

    unsigned long make_color(char* hex)
    {
        unsigned long color = 0;

        if (*hex == '#') hex++;

        sscanf(hex, "%x", &color);

        return color;
    };

    void render_rect(SDL_Surface* s,int x,int y, int w, int h,unsigned long color)
    {
        SDL_Rect r;
        r.x = x;
        r.y = y;
        r.h = h;
        r.w = w;
        SDL_FillRect(s, &r, color);
    };

    // -- shall we render ?
    bool render_is_viewable(int x, int y, int w, int h)
    {
       if (x <= SCREEN_WIDTH && (y < SCREEN_HEIGHT && y > (0 - h)))
        return true;

        return false;
    };



    void calculate_text(html_tag *c,int ix, int iy)
    {
        // -- locals
        char* res = 0;
        int x = ix;
        int y = iy;
        int word_height = 0;
        int word_len = 0;
        int rows = 1;
        SDL_Rect word_rect = {0,0,0,0};
        SDL_Rect box = {0,0,0,0};

        // -- defaults
        r_co->position.x = x;
        r_co->position.y = y;
        r_co->r_preformatted = false;
        r_co->r_padding.x = r_co->r_padding.y = r_co->r_padding.h = r_co->r_padding.w = 0;
        r_co->r_color = 0x0; //black
        r_co->r_fontweight = TTF_STYLE_NORMAL;
        r_co->r_align = AL_LEFT;
        r_co->r_fontsize = SZ_NORMAL;

        // -- handle text

        html_tag *node = c;

        while(node)
        {
            if (node->tag_hash == hash_html) break; // first node

            if (last_tag->tag_hash != hash_a)
            {
                if (!res) {
                    res = get_attribute_value(node,a_hash_color);
                    if (res) r_co->r_color = make_color(res);
                    else
                    {
                        // -- <body text="#ffffff">
                        res = get_attribute_value(node,a_hash_text);
                        if (res) r_co->r_color = make_color(res);
                    }

                }
            }else{
                r_co->r_color = 0x0000ff;//r_co->_ralink;
            }
            if (node->tag_hash == hash_b || node->tag_hash == hash_strong) r_co->r_fontweight |= TTF_STYLE_BOLD;
            if (node->tag_hash == hash_i || node->tag_hash == hash_em) r_co->r_fontweight |= TTF_STYLE_ITALIC;
            if (node->tag_hash == hash_h1 || node->tag_hash == hash_big) r_co->r_fontsize = SZ_H1;
            if (node->tag_hash == hash_h2) r_co->r_fontsize = SZ_H2;
            if (node->tag_hash == hash_h3) r_co->r_fontsize = SZ_H3;
            if (node->tag_hash == hash_h4 || node->tag_hash == hash_small) r_co->r_fontsize = SZ_H4;
            if (node->tag_hash == hash_h5) r_co->r_fontsize = SZ_H5;
            if (node->tag_hash == hash_h6) r_co->r_fontsize = SZ_H6;
            if (node->tag_hash == hash_blockquote) r_co->r_padding.x = r_co->r_fontsize * 2;
            if (node->tag_hash == hash_pre) r_co->r_preformatted = true;

            if (!box.w)
            {
                box.x = node->box.x;
                box.y = node->box.y;
                box.h = node->box.h;
                box.w = node->box.w;
            }
            // -- needs more work!
           // if (node->tag_hash == hash_center) r_co->r_align = AL_CENTER;
            node = node->parent_tag;
        }

        y += r_co->r_padding.h;

        // -- needs to be set for correct sizing
        fnts.set_font_size(r_co->r_fontsize);
        fnts.set_style(r_co->r_fontweight);

        // -- do the alignment first on the whole sentence, we are splitting the words below
        if (r_co->r_align == AL_CENTER) x = (int)((page_width / 2) - (fnts.get_length_px((char*)c->text.c_str()) / 2));


        // -- Render each word to the page
        char* word_ptr = (char*)c->text.c_str();


        while(*word_ptr)
        {
            char* start_of_word = word_ptr;

            //&
            if (*word_ptr == '&')
            {
                word_ptr = render_text_ent(c,word_ptr,x,y,&word_rect);
                x += word_rect.w;
                continue;
            }

            // spaces,tabs
            if(isspace(*word_ptr)) {
                switch(*word_ptr)
                {
                    case ' ':
                        word_rect.w = fnts.get_length_px((char*)" ");
                        x += word_rect.w;
                    break;

                    case '\n':
                        if (r_co->r_preformatted)
                        {
                            word_height = fnts.get_height_px((char*)"\n");

                            y += word_height;
                            x = box.x;//bbox ? bbox->x : 0;
                        }else{
                            word_ptr++;
                            continue;
                        }
                    break;

                    case '\t':
                        if (r_co->r_preformatted)
                        {
                            word_len = fnts.get_length_px((char*)"\t") * 8;
                            x += word_len;
                        }else{
                            word_ptr++;
                            continue;
                        }
                    break;

                }


                word_ptr++;
                continue;
            }

            while(*word_ptr && !isspace(*word_ptr) && *word_ptr != '&')
                ++word_ptr;


            char* word = new char[word_ptr-start_of_word+1];
            if (!word) return;

            strncpy(word,start_of_word,(word_ptr-start_of_word));
            word[(word_ptr-start_of_word)] = 0;

            word_len = fnts.get_length_px(word);
            word_height = fnts.get_height_px(word);


            //if (box.w)
            {
                if ((word_len+x) > (box.w))//limit_x)
                {
                    y += word_height;
                    x = box.x;
                    rows++;

                }

            }
           /* else if (word_len+x > page_width)
            {
                y += word_height;


                if (y >= nextline) x = 0;//start_x;
                else x = nextx;

                rows++;
            }*/

             // -- if ! render we need to get the height of the current text
            word_rect.h = fnts.get_height_px(word);
            word_rect.w = fnts.get_length_px(word);

            x += word_rect.w;

            delete [] word;

        }

        c->box.x = x;
        c->box.y = y;
        c->box.h = (word_rect.h * rows);
        c->box.w = rows != 1 ? x : x - ix;


        r_co->position.h = (word_rect.h * rows);
        r_co->position.x = ix;
        r_co->position.y = iy;
        if (rows > 1)
        {
            r_co->position.w= box.w;
            //if (bbox) r_co->position.w = bbox->w;
            //else r_co->position.w = page_width;

        }else r_co->position.w = x ;

        // save bounding box
        r_co->box = r_co->position;
        r_co->box.x = box.x;

        //r_co->position.w = c->w;
        if (nextline < y + word_rect.h) nextline = y + word_rect.h;


        return;

    };
    char* render_text_ent(html_tag *c, char* word_ptr, int x, int y,SDL_Rect* o_r)
    {
        char* start_of_word = word_ptr+1; // bypass '&'

        while(*word_ptr && !isspace(*word_ptr) && *word_ptr != ';')
            ++word_ptr;

        char* word = new char[word_ptr-start_of_word+1];

        if (!word) return word_ptr;

        strncpy(word,start_of_word,(word_ptr-start_of_word));
        word[(word_ptr-start_of_word)] = 0;

        int word_len = fnts.get_length_px(word);
        int word_height = fnts.get_height_px(word);

        word_ptr++; // bypass ';'

        char out[2] =  {0};

        // create lookup hashes --- TO DO !!!! --- see -- http://www.w3schools.com/tags/ref_symbols.asp

        if (strcmp(word,"copy")==0) out[0] = char(169); /* Copyright */
        if (strcmp(word,"trade")==0) out[0] = char(153); /* Trademark */
        if (strcmp(word,"nbsp")==0) out[0] = ' '; /* no break space*/

        *o_r = fnts.text(screen,out,view_x+(x+r_co->r_padding.x), view_y + y,0,0);

        return word_ptr;

    }
/*
    void render_text(html_tag *c,int ix, int iy, bool render = 1, r_rect* bbox = 0)
    {
        // -- locals
        char* res = 0;
        int x = ix;
        int y = iy;
        int word_height = 0;
        int word_len = 0;
        int rows = 1;
        SDL_Rect word_rect = {0,0,0,0};

        // -- defaults
        r_co->r_preformatted = false;
        r_co->r_padding.x = r_co->r_padding.y = r_co->r_padding.h = r_co->r_padding.w = 0;
        r_co->r_color = 0x0; //black
        r_co->r_fontweight = TTF_STYLE_NORMAL;
        r_co->r_align = AL_LEFT;
        r_co->r_fontsize = SZ_NORMAL;

        // -- handle text

        html_tag *node = c;

        while(node)
        {
            if (last_tag->tag_hash != hash_a)
            {
                if (!res) {
                    res = get_attribute_value(node,a_hash_color);
                    if (res) r_co->r_color = make_color(res);
                    else
                    {
                        // -- <body text="#ffffff">
                        res = get_attribute_value(node,a_hash_text);
                        if (res) r_co->r_color = make_color(res);
                    }

                }
            }else{
                r_co->r_color = 0x0000ff;//r_co->_ralink;
            }
            if (node->tag_hash == hash_b || node->tag_hash == hash_strong) r_co->r_fontweight |= TTF_STYLE_BOLD;
            if (node->tag_hash == hash_i || node->tag_hash == hash_em) r_co->r_fontweight |= TTF_STYLE_ITALIC;
            if (node->tag_hash == hash_h1 || node->tag_hash == hash_big) r_co->r_fontsize = SZ_H1;
            if (node->tag_hash == hash_h2) r_co->r_fontsize = SZ_H2;
            if (node->tag_hash == hash_h3) r_co->r_fontsize = SZ_H3;
            if (node->tag_hash == hash_h4 || node->tag_hash == hash_small) r_co->r_fontsize = SZ_H4;
            if (node->tag_hash == hash_h5) r_co->r_fontsize = SZ_H5;
            if (node->tag_hash == hash_h6) r_co->r_fontsize = SZ_H6;
            if (node->tag_hash == hash_blockquote) r_co->r_padding.x = r_co->r_fontsize * 2;
            if (node->tag_hash == hash_pre) r_co->r_preformatted = true;
            // -- needs more work!
           // if (node->tag_hash == hash_center) r_co->r_align = AL_CENTER;
            node = node->parent_tag;
        }

        y += r_co->r_padding.h;
        fnts.set_font_size(r_co->r_fontsize);
        fnts.set_style(r_co->r_fontweight);
        fnts.change_color((r_co->r_color >> 16), ((r_co->r_color >> 8) & 0xff),(r_co->r_color & 0xff));

        // -- do the alignment first on the whole sentence, we are splitting the words below
        if (r_co->r_align == AL_CENTER) x = (int)((page_width / 2) - (fnts.get_length_px((char*)c->text.c_str()) / 2));


        // -- Render each word to the page
        char* word_ptr = (char*)c->text.c_str();


        while(*word_ptr)
        {
            char* start_of_word = word_ptr;

            //&
            if (*word_ptr == '&')
            {
                word_ptr = render_text_ent(c,word_ptr,x,y,&word_rect);
                x += word_rect.w;
                continue;
            }

            // spaces,tabs
            if(isspace(*word_ptr)) {
                switch(*word_ptr)
                {
                    case ' ':

                        if (render)
                            word_rect = fnts.text(screen," ",view_x + (x+r_co->r_padding.x), view_y + y,0,0);
                        else word_rect.w = fnts.get_length_px((char*)" ");

                        x += word_rect.w;
                    break;

                    case '\n':
                        if (r_co->r_preformatted)
                        {
                            word_height = fnts.get_height_px((char*)"\n");

                            y += word_height;
                            x = bbox ? bbox->x : 0;
                        }else{
                            word_ptr++;
                            continue;
                        }
                    break;

                    case '\t':
                        if (r_co->r_preformatted)
                        {
                            word_len = fnts.get_length_px((char*)"\t") * 8;
                            x += word_len;
                        }else{
                            word_ptr++;
                            continue;
                        }
                    break;

                }


                word_ptr++;
                continue;
            }

            while(*word_ptr && !isspace(*word_ptr) && *word_ptr != '&')
                ++word_ptr;


            char* word = new char[word_ptr-start_of_word+1];
            if (!word) return;

            strncpy(word,start_of_word,(word_ptr-start_of_word));
            word[(word_ptr-start_of_word)] = 0;

            word_len = fnts.get_length_px(word);
            word_height = fnts.get_height_px(word);


            if (bbox)
            {
                if ((word_len+x)-bbox->x > (bbox->w))//limit_x)
                {
                    y += word_height;
                    x = bbox->x;
                    rows++;

                }

            }
            else if (word_len+x > page_width)
            {
                y += word_height;
                if (y >= nextline) x = bbox ? bbox->x : 0;//start_x;
                else x = nextx;

                rows++;
            }

            if (render)
            {
                word_rect = fnts.text(screen,word,view_x+(x+r_co->r_padding.x), view_y + y,0,0);
            }else{
                 // -- if ! render we need to get the height of the current text
                word_rect.h = fnts.get_height_px(word);
                word_rect.w = fnts.get_length_px(word);
            }
            x += word_rect.w;

            delete [] word;

        }

        c->x = x;
        c->y = y;
        c->h = (word_rect.h * rows);
        c->w = rows != 1 ? x : x - ix;

        if (render) if (nextline < y + word_rect.h) nextline = y + word_rect.h;


        return;

    };
*/

    //  -- text
    void render_text(render_object* ro)
    {
        // -- locals

        int x = ro->position.x;
        int y = ro->position.y;
        int word_height = 0;
        int word_len = 0;
        int rows = 1;
        SDL_Rect word_rect = {0,0,0,0};



        // -- handle text
        html_tag *c = ro->tag;

        fnts.set_font_size(ro->r_fontsize);
        fnts.set_style(ro->r_fontweight);
        fnts.change_color((ro->r_color >> 16), ((ro->r_color >> 8) & 0xff),(ro->r_color & 0xff));

        // -- do the alignment first on the whole sentence, we are splitting the words below
        if (ro->r_align == AL_CENTER) x = (int)((page_width / 2) - (fnts.get_length_px((char*)c->text.c_str()) / 2));

        if (ro->mouse_over) fnts.change_color(255, 0,0); // test

        // -- Render each word to the page
        char* word_ptr = (char*)c->text.c_str();

        while(*word_ptr)
        {
            char* start_of_word = word_ptr;

            //&
            if (*word_ptr == '&')
            {
                word_ptr = render_text_ent(c,word_ptr,x,y,&word_rect);
                x += word_rect.w;
                continue;
            }

            // spaces,tabs
            if(isspace(*word_ptr)) {
                switch(*word_ptr)
                {
                    case ' ':
                        word_rect = fnts.text(screen," ",view_x + (x+r_co->r_padding.x), view_y + y,0,0);
                        x += word_rect.w;
                    break;

                    case '\n':
                        if (r_co->r_preformatted)
                        {
                            word_height = fnts.get_height_px((char*)"\n");

                            y += word_height;
                            x = ro->position.x ? ro->position.x : 0;
                            //x = bbox ? bbox->x : 0;
                        }else{
                            word_ptr++;
                            continue;
                        }
                    break;

                    case '\t':
                        if (r_co->r_preformatted)
                        {
                            word_len = fnts.get_length_px((char*)"\t") * 8;
                            x += word_len;
                        }else{
                            word_ptr++;
                            continue;
                        }
                    break;

                }


                word_ptr++;
                continue;
            }

            while(*word_ptr && !isspace(*word_ptr) && *word_ptr != '&')
                ++word_ptr;


            char* word = new char[word_ptr-start_of_word+1];
            if (!word) return;

            strncpy(word,start_of_word,(word_ptr-start_of_word));
            word[(word_ptr-start_of_word)] = 0;

            word_len = fnts.get_length_px(word);
            word_height = fnts.get_height_px(word);

            //if (ro->b_box)
            //{
                if ((x+word_len)-ro->box.x > ro->box.w)//(ro->position.w))
                {
                    y += word_height;
                    x = ro->box.x;
                    rows++;
                }
          /*  }else{
                if ((x+word_len) > page_width)//(ro->position.w))
                {
                    y += word_height;
                    x = 0;//ro->position.x;
                    rows++;
                }
            }*/
            word_rect = fnts.text(screen,word,view_x+(x+ro->r_padding.x), view_y + y,0,0);
            x += word_rect.w;

            delete [] word;

        }


        return;

    };
    // -- BODY
    void render_body(render_object* ro)
    {

        render_rect(screen,0,0,SCREEN_WIDTH,SCREEN_HEIGHT,ro->r_bgcolor); // white bg as default
        if (ro->r_background) {

            SDL_Rect r;

            for(int y=0;y<page_height;y+=ro->r_background->h)
            {
                for(int x=0;x<page_width;x+=ro->r_background->w)
                {
                    r.x = x;
                    r.y = y + view_y;
                    r.h = ro->r_background->h;
                    r.w = ro->r_background->w;

                    if (r.y  < SCREEN_HEIGHT)
                        SDL_BlitSurface(ro->r_background,0,screen,&r);
                }
            }
        }

    }

    // -- HR
    void render_hr(render_object* ro)
    {
        hlineColor(screen, ro->position.x + view_x, page_width, ro->position.y + view_y, 0x0000ff);
    };

    // -- IMG
    void render_image(render_object* ro)//html_tag *c,int x, int y)
    {
        SDL_Rect rect = ro->position;

        rect.x += view_x;
        rect.y += view_y;
        // -- render
        SDL_Rect save = rect; // must save real rect as SDL_BlitSurface will change it if image is off screen
        // -- we in a viewable area
        if (render_is_viewable(rect.x,rect.y,rect.w,rect.h))
        {

            if (ro->img)
            {
                // -- check if the image needs resizing
                if (rect.w == ro->img->w && rect.h == ro->img->h) {
                    SDL_BlitSurface(ro->img,0,screen,&rect);
                }else{
                    SDL_Rect src_rect = rect;
                    src_rect.y = src_rect.x = 0;

                    SDL_SoftStretch(ro->img,0,screen,&rect);
                }
            }else render_rect(screen,ro->position.x,ro->position.y,rect.w,rect.h,0); // placeholder
        }

        // set the h,w,x,y
/*        c->x = x;
        c->y = y;
        c->h = save.h;
        c->w = save.w;
*/
        return;
    };

    render_object* new_object(html_tag* ct)
    {
        r_co = new render_object(this,ct);
        r_objs.push_back(r_co);

        return r_co;
    };




    void render_set(SDL_Event* e)
    {
        for(int i =0; i<(int)r_objs.size();i++)
        {
            if (r_objs[i]->box.x < view_x + SCREEN_WIDTH &&
                view_y + r_objs[i]->box.y < SCREEN_HEIGHT && view_y + r_objs[i]->box.y >= 0)
                {
                    r_objs[i]->render(e);
                    // test rects
                    rectangleColor( screen,
                                    r_objs[i]->box.x + view_x,
                                    r_objs[i]->box.y + view_y,
                                    view_x + r_objs[i]->box.x + r_objs[i]->box.w,
                                    view_y + r_objs[i]->box.y + r_objs[i]->box.h,
                                    0xff00ffff);
                }else if (r_objs[i]->h == hash_body) { // must render body
                     r_objs[i]->render(e);

                }
        }
    };

    bool rendering_table;

    // -- core of the rendering ... call once to set up everything
    void render_start()
    {
        html_tag *c = 0;
        int default_br = 12; // default
        char* res;
        rendering_table = false;
        nextline = nextx = p_x = p_y = 0;

        last_tag = 0;

        int i = -1;
        c = doc->html_t[0]; // start tag

        while (c)
        {
            i++;
            page_height = p_y;

            last_tag = c;

            c = doc->html_t[i];
            if (!c) break;


            if (last_tag) {
                if (c->tag_hash == hash__comment ||
                    last_tag->tag_hash == hash_title ||
                    last_tag->tag_hash == hash_meta ||
                    last_tag->tag_hash == hash_link ||
                    last_tag->tag_hash == hash_html
                    ) continue; // don't renders
            }



            // -- body
            if (c->tag_hash == hash_body)
            {
                render_object* x  = new_object(c);

                // alink
                res = get_attribute_value(c,a_hash_alink);
                if (res)  x->r_alink = make_color(res);

                // bgcolor
                res = get_attribute_value(c,a_hash_bgcolor);
                if (res) x->r_bgcolor = make_color(res);

                // background
                res = get_attribute_value(c,a_hash_background);
                if (res) x->r_background = load_image(res);

                // body box is entire page!
                c->box.x = 0;
                c->box.y = 0;
                c->box.w = page_width;
                c->box.h = page_height;


                continue;
            }



            // -- HR
            if (c->tag_hash == hash_hr)
            {
                render_object* x = new_object(c);

                p_y = nextline;

                x->position.h = 10;
                x->position.x = 0;
                x->position.y = p_y + 10;
                x->position.w = 100;

                // -- bb
                x->box = x->position;

                continue;
            }

            // -- img
            if (c->tag_hash == hash_img) {

                render_object* x = new_object(c);

                x->position.x = p_x;
                x->position.y = p_y;

                int align = AL_LEFT;

                // height
                res = get_attribute_value(c,a_hash_height);
                if (res) x->position.h = atoi(res);

                // width
                res = get_attribute_value(c,a_hash_width);
                if (res) x->position.w = atoi(res);

                // load the image ... src
                res = get_attribute_value(c,a_hash_src);
                x->img = load_image(res);

                if (x->img)
                {
                    if (x->position.w == 0) x->position.w = x->img->w;
                    if (x->position.h == 0) x->position.h = x->img->h;
                }

                // -- bb
                x->box = x->position;
             /*   html_tag *node = c;

                while(node)
                {
                   // if (node->tag_hash == hash_center) align = AL_CENTER;

                    node = node->parent_tag;
                }

                if (align == AL_CENTER) {
                    x = (int)((page_width / 2) - (rect.w / 2));
                }
                */
                //render_image(c,p_x,p_y);

                p_x += x->position.w ;

                nextline = p_y + x->position.h;
                if (p_x >= page_width) {
                    p_y = nextline;
                    p_x = 0;
                }

                nextx = p_x;
                continue;
            }



            if (/* start of tag */
                c->tag_hash == hash_div || c->tag_hash == hash_h1 || c->tag_hash == hash_pre ||
                c->tag_hash == hash_h2 || c->tag_hash == hash_h3 || c->tag_hash == hash_h4 ||
                c->tag_hash == hash_h5 || c->tag_hash == hash_h6 || c->tag_hash == hash_p ||
                c->tag_hash == hash_blockquote
                )
            {
                if (p_x != 0) p_y = nextline;

                p_x = 0;//nextx;


            }

            if (/* end tags */
                c->tag_hash == hash__div || c->tag_hash == hash__h1 ||
                c->tag_hash == hash__h2 || c->tag_hash == hash__h3 || c->tag_hash == hash__h4 ||
                c->tag_hash == hash__h5 || c->tag_hash == hash__h6 || c->tag_hash == hash__p ||
                c->tag_hash == hash__pre || c->tag_hash == hash__blockquote
            )
            {
               p_y = nextline;
               p_y += default_br;
               p_x = 0;//nextx;

            }

            if (c->tag_hash == hash_p || c->tag_hash == hash__p || c->tag_hash == hash__pre ||
                c->tag_hash == hash_pre || c->tag_hash == hash__blockquote || c->tag_hash == hash_blockquote)
                    p_y += default_br;

            if (c->tag_hash == hash_br)
            {
                p_y += default_br;

                if (p_y < nextline)
                {
                    p_y = nextline;
                }
                if (rendering_table)
                {
                    p_x = table_data.x_start + (table_data.col_i > 0 ? p_x : table_data.x_start);
                }else p_x = nextx;

                continue;
            }

            if (c->tag_hash == hash_table || hash__table ||
                c->tag_hash == hash_tr || hash__tr ||
                c->tag_hash == hash_td || hash__td
                ) render_table(i);



            if (c->text.length() > 0)
            {
                render_object* x  = new_object(c);

                if (rendering_table)
                {
                    int col_start_px = table_data.x_start + (table_data.col_i > 0 ? p_x : table_data.x_start);
                    b_box.x = col_start_px;
                    b_box.w = table_data.col_widths[table_data.col_i];

                    r_co->ww_startx = table_data.col_i > 0 ? table_data.col_widths[table_data.col_i-1] : 0;

                    calculate_text(c,p_x,p_y);
                    p_x = c->box.x;
                    p_y = c->box.y;
                    nextx = b_box.x;
                }else{


                    calculate_text(c,p_x,p_y);

                    p_x = c->box.x;
                    p_y = c->box.y;
                    nextx = 0;
                }



            }


        }



    };

    // probably very slow !!! if someone has a better idea then people do it!
    void calculate_table(int index)
    {
        int index_start = index;
        html_tag* c = doc->html_t[index];

        // set up
        rendering_table = true;
        table_data.x_start = 0;
        table_data.y_start = p_y;
        table_data.row_i = 0;
        table_data.col_i = 0;
        table_data.num_cols = 0;
        table_data.num_rows = 0;
        memset(table_data.col_widths,0,sizeof(int)*MAX_TABLE_COLS);
        memset(table_data.col_min_widths,0,sizeof(int)*MAX_TABLE_COLS);
        memset(table_data.col_fixed_widths,0,sizeof(int)*MAX_TABLE_COLS);
        memset(table_data.col_height,0,sizeof(int)*MAX_TABLE_ROWS);
        memset(table_data.row_fixed_heights,0,sizeof(int)*MAX_TABLE_ROWS);


        // caculate number of columns and rows
        while(c)
        {
            if (c->tag_hash == hash_td) table_data.num_cols ++;
            if (c->tag_hash == hash_tr) table_data.num_rows ++;

            index++;
            c = doc->html_t[index];

            if (c->tag_hash == hash__table) break;
        }

        table_data.num_cols =  table_data.num_cols / table_data.num_rows;

        // pre-calculate the size of each column
        int column_index = 0;
        int row_index = 0;
        int minimum_word_size = 0;

        index = index_start;

        table_data.max_width = page_width; // could be set with style but at this point this is a start
        c = doc->html_t[index];
        int row_h = 0;

        while(c)
        {
            if (c->tag_hash == hash_td)
            {
                if(!table_data.col_fixed_widths[column_index])
                {
                    table_data.col_widths[column_index] = table_data.col_fixed_widths[column_index] = get_attribute_value_int(c,a_hash_width,hash_td);
                }

                row_h = 0;
                b_box.x = 0;
                b_box.y = 0;

            }

            if (c->tag_hash == hash_tr)
            {
                if(!table_data.row_fixed_heights[column_index])
                {
                    table_data.row_fixed_heights[row_index] = table_data.row_fixed_heights[row_index] = get_attribute_value_int(c,a_hash_height,hash_tr);
                }
            }

            if (c->tag_hash == hash__td)
                column_index++;

            if (c->tag_hash == hash__tr)
            {
                column_index = 0;
                row_index++;
            }



            if (c->text.length() > 0)
            {
                if (!table_data.col_fixed_widths[column_index]) // width set by "width" property
                {

                    int text_size = fnts.get_length_px((char*)c->text.c_str());

                    if (text_size > table_data.col_widths[column_index])
                        table_data.col_widths[column_index] = text_size;

                    // -- need to get minimum WORD size also ( this is used for the column min width
                    minimum_word_size = 0;
                    char* word_ptr = (char*)c->text.c_str();
                    char* word = 0;

                    while(*word_ptr)
                    {
                        char* start_of_word = word_ptr;
                        while(*word_ptr && !isspace(*word_ptr))
                            ++word_ptr;

                        int c_size = word_ptr - start_of_word;

                        word = new char[word_ptr-start_of_word+1];
                        if (word)
                        {
                            strncpy(word,start_of_word,(word_ptr-start_of_word));
                            word[(word_ptr-start_of_word)] = 0;

                            c_size = fnts.get_length_px(word);
                            if (minimum_word_size < c_size)
                                table_data.col_min_widths[column_index] = c_size;
                        }

                        if(*word_ptr) ++word_ptr; // carry on
                    }

                } // fixed width

                /*
                    Deal with rows
                */

               // if (!table_data.row_fixed_heights[row_index]) // height set by "height" property
               // {

                    b_box.w = (table_data.col_fixed_widths[column_index] ? table_data.col_fixed_widths[column_index] : table_data.col_widths[column_index]);

                    calculate_text(c,0,0); // no render, just calculate

                    b_box.x = c->box.x;
                    row_h += c->box.h;

                    if (row_h > table_data.col_height[row_index])
                        table_data.col_height[row_index] = row_h;


               // } else {
               //     if (table_data.row_fixed_heights[row_index] > table_data.col_height[row_index])
               //         table_data.col_height[row_index] = table_data.row_fixed_heights[row_index];

               // }


            }



            // move on
            index++;
            c = doc->html_t[index];

            if (c->tag_hash == hash__table) break;
        }

        int i = 0;


        // total width
        int total_w = 0;
        for(i =0; i < table_data.num_cols; i++) {
            total_w += table_data.col_widths[i];

        }



        if (total_w > table_data.max_width) // calculate the column sizes if table is bigger than page
        {
            // make the column widths a percentage of the max_width
            for(i =0; i < table_data.num_cols; i++)
            {
                if (!table_data.col_fixed_widths[i])
                {
                    int scale_width = (int)(((float)table_data.max_width / total_w) * (float)table_data.col_widths[i]);
                    table_data.col_widths[i] = max(scale_width,table_data.col_min_widths[i]);

                    //could still overrun the page width !!! need to reduce the bigger cols
                }

            }
        }
    }

    // -- tables -- render
    int render_table(int index)
    {

        html_tag* c = doc->html_t[index];
        if (!c) return index;

        // start
        if (c->tag_hash == hash_table)
        {
            // slowwwwwww......
            calculate_table(index);

            if (p_x != 0) p_y = nextline;
            p_x = 0;
            table_data.y_start = p_y;


           // render_table_border();
        }

        // end
        if (c->tag_hash == hash__table)
        {
            rendering_table = false;
            table_data.row_i = 0;
            table_data.col_i = 0;
        }

         if (c->tag_hash == hash__tr) {
            table_data.row_i++;
            p_x = table_data.x_start;
            p_y = table_data.y_start;
            table_data.col_i = 0;
            for(int i =0; i < table_data.row_i; i++)
                p_y += table_data.col_height[i] ;


        }

        if (c->tag_hash == hash__td) {
            table_data.col_i++;
            p_x = table_data.x_start;
            p_y = table_data.row_i > 0 ? table_data.y_start+table_data.col_height[table_data.row_i-1] : table_data.y_start;
            for(int i =0; i < table_data.col_i; i++)
                p_x += table_data.col_widths[i];

        }

        if (c->tag_hash == hash_td) {
            nextline = table_data.row_i > 0 ? table_data.y_start+table_data.col_height[table_data.row_i-1] : table_data.y_start;
            nextx = table_data.col_widths[table_data.col_i];
        }


        return index;
    };

    void render_table_border()
    {
        int x1 = 0;
        int y1 = 0;

        /* V lines */
        // -- first line
        vlineColor(screen, view_x+table_data.x_start, view_y+table_data.y_start, view_y+table_data.y_start+table_data.col_height[0], 0xffffffff);
        // -- loop and do the rest of the V lines
        for(int y =0; y < table_data.num_rows; y++)
        {

            for(int x =0; x < table_data.num_cols; x++)
            {
                x1 += table_data.col_widths[x];
                vlineColor(screen, view_x+(table_data.x_start+x1), view_y+(table_data.y_start+y1), view_y+(table_data.y_start+y1+table_data.col_height[y]), 0xffffffff);

            }
            y1 += table_data.col_height[y];
            x1 = 0;

        }

        /* H lines */


    };

};


#endif // RENDER_H_INCLUDED
